package com.yx.crawler.runtime;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.apache.commons.httpclient.Header;  
import org.apache.commons.httpclient.HttpClient;  
import org.apache.commons.httpclient.HttpException;  
import org.apache.commons.httpclient.HttpMethod;  
import org.apache.commons.httpclient.HttpStatus;  
import org.apache.commons.httpclient.methods.GetMethod;  
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;  

public final class ProxyServerManager extends Thread {
	private final List<ProxyServer> proxys = new ArrayList<ProxyServer>();
	private final String userAgent = "Mozilla/4.0 (compatible; MSIE 7.0; NT 5.1; GTB5; .NET CLR 2.0.50727; CIBA)";
	private static ProxyServerManager instance = null;
	public final static int MAX_PROXY_NUMBER = 1000;
	public final static long PROXY_AVERAGE_ACCESS_TIME = 1000;

	public static ProxyServerManager getInstance() {
		if (instance == null) {
			instance = new ProxyServerManager();
		}
		return instance;
	}

	private ProxyServerManager() {
		this.start();
	}

	public static ProxyServer get() {
		return getInstance().proxy();
	}

	private synchronized ProxyServer proxy() {
		int proxysSize = 0;
		long time = 500;
		long beginTime = System.currentTimeMillis();
		while (true) {
			proxysSize = proxys.size();
			if (proxysSize > 0) {
				time = PROXY_AVERAGE_ACCESS_TIME / proxysSize;
			}
			time = time > 1 ? time : 1;
			long hasSleeped = System.currentTimeMillis() - beginTime;
			if (proxysSize <= 0 || (proxysSize > 0 && time > hasSleeped)) {
				synchronized (this) {
					try {
						wait(time);
					} catch (Exception e) {
					}
				}
			} else {
				break;
			}
		}
		proxysSize = proxys.size();
		java.util.Random random = new java.util.Random();
		int index = random.nextInt(proxysSize);
		return proxys.get(index);
	}

	public synchronized void remove() {

	}

	public void run() {
		int pageIdx = 0;
		while (true) {
			if (MAX_PROXY_NUMBER > proxys.size()) {
				pageIdx++;
				if (pageIdx > 10)
					pageIdx = pageIdx - 10;
				initProxyServers(pageIdx);
				daemonSleep(1000);
			} else {
				daemonSleep(30 * 1000);
			}
		}
	}

	private void initProxyServers(int pageIdx) {
		try {
			String url = "http://www.xicidaili.com/nn/" + pageIdx;
			Document document = Jsoup.connect(url).userAgent(userAgent).get();
			Elements elements = document.getElementsByTag("tbody").get(0).getElementsByTag("tr");
			for (Element element : elements) {
				Elements tdElements = element.getElementsByTag("td");
				if (tdElements != null && tdElements.size() > 6) {
					if ("高匿".equals(tdElements.get(5).text())) {
						ProxyServer proxyServer = new ProxyServer(tdElements.get(2).text(),
								Integer.parseInt(tdElements.get(3).text()));						
						if (proxyServer.isOK()) {
							System.out.println("检索到代理服务器：" + proxyServer.id() + "...................OK!");							
							proxys.add(proxyServer);
						}else{
							System.out.println("检索到代理服务器：" + proxyServer.id() + "...................NO!");	
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void daemonSleep(long time) {
		try {
			sleep(time);
		} catch (Exception e) {
		}
	}

	public class ProxyServer {
		String id,host;
		int port;
		Proxy proxy;

		public ProxyServer(String host, int port) {
			this.host=host;
			this.port=port;
			this.id = host + ":" + port;		
			proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port));
		}

		public String id() {
			return id;
		}

		public Proxy proxy() {
			return proxy;
		}

		public boolean isOK() {
			long time = responseTime1();
			if (time > 0 && time < 3000) {
				return true;
			} else {
				return false;
			}
		}

		public long responseTime1() {
			int statusCode = 0;
			String reqUrl="http://www.baidu.com";
			long t=System.currentTimeMillis();
			try {
				HttpClient httpClient = new HttpClient();
				httpClient.getHostConfiguration().setProxy(host, port);
				int connectionTimeout = 5000;
				int soTimeout = 5000;
				httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
				httpClient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);
				httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,null);
				HttpMethod method = new GetMethod(reqUrl);
				statusCode = httpClient.executeMethod(method);
				if (statusCode != HttpStatus.SC_OK) {					 
					 return System.currentTimeMillis()-t;
				}else{
					 return -1;
				}
			} catch (Exception e) {
				return -1;
			}
		}

		public long responseTime() {
			long t = System.currentTimeMillis();
			HttpURLConnection httpUrlConnetion = null;
			try {
				final URL website = new URL("http://www.baidu.com");
				httpUrlConnetion = (HttpURLConnection) website.openConnection(proxy);
				// httpUrlConnetion.setConnectTimeout(3000);
				// httpUrlConnetion.connect();
				BufferedReader br = new BufferedReader(new InputStreamReader(httpUrlConnetion.getInputStream()));
				StringBuilder buffer = new StringBuilder();
				String str;
				while ((str = br.readLine()) != null) {
					buffer.append(str);
				}
				Document doc = Jsoup.parse(buffer.toString());
				return System.currentTimeMillis() - t;
			} catch (Exception e) {
				return -1;
			}
		}
	}

	public static void main(String[] args) throws Exception {
		ProxyServerManager.getInstance();
		// for(int i=0;i<10;i++){
		// System.out.println(ProxyServerManager.get().id());
		// }
	}

}
